package com.dingreading.cloud.admin.controller;

import com.alibaba.excel.EasyExcel;
import com.dingreading.cloud.admin.dto.CmorderDto;
import com.dingreading.cloud.admin.dto.CmservicesDto;
import com.dingreading.cloud.admin.dto.vo.CallNameVoV3;
import com.dingreading.cloud.admin.dto.vo.MemberAccumulateVO;
import com.dingreading.cloud.admin.entity.CaCallNames;
import com.dingreading.cloud.admin.entity.Cmservices;
import com.dingreading.cloud.admin.entity.Stores;
import com.dingreading.cloud.admin.service.CaCallNamesService;
import com.dingreading.cloud.admin.service.CmordersService;
import com.dingreading.cloud.admin.service.CmservicesService;
import com.dingreading.cloud.admin.service.StoresService;
import com.dingreading.cloud.admin.util.ScheduleUtil;
import com.dingreading.cloud.admin.util.bean.CmorderUtil;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.excel.ExcelHandler;
import com.dingreading.cloud.common.util.excel.RowBean;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Table;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/system/callName")
@Api(tags = "总部-会员活动记录管理")
public class CallNameController {

    @Resource
    protected CaCallNamesService callNameService;
    @Resource
    protected CmservicesService cmservicesService;
    @Resource
    protected CmordersService cmordersService;
    @Resource
    protected StoresService storesService;


    @ApiOperation(value = "导出自营门店所有会员的活动记录并统计活动总数")
    @PostMapping(value = "/exportSelfCallList", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportSelfCallList(
            HttpServletResponse response,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
//        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
//            // 获取本月的第一天和最后一天
//            Date monthMinDate = DateUtil.getMonthMinDate();
//            Date monthMaxDate = DateUtil.getMonthMaxDate();
//            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
//            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
//        }

        List<CaCallNames> list = callNameService.getMemberCallListV3(AccountUtil.SELF_CORP_UID, null,
                null, null, beginDate, endDate, null, null, null,
                Arrays.asList(1, 2), Arrays.asList(1, 2));

        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("未查询到数据");

        Map<String, List<CaCallNames>> memberMap = list.stream().collect(Collectors.groupingBy(CaCallNames::getMemberUid));

        int firstStartRow = 1;
        int firstEndRow = 0;
        // 需要合并的行号
        List<RowBean> firstRows = new ArrayList<>();
        // 需要合并的列号
        List<Integer> firstColumns = Lists.newArrayList(0, 1);

        List<CallNameVoV3> voList = new ArrayList<>();
        for (Map.Entry<String, List<CaCallNames>> entry : memberMap.entrySet()) {
            List<CaCallNames> memberCallList = entry.getValue();
            int lessonNum = memberCallList.size();

            Map<String, List<CaCallNames>> teacherMap = memberCallList.stream().collect(Collectors.groupingBy(CaCallNames::getTeacherUid));
            int size = teacherMap.size();
            firstEndRow += size;
            // 合并必须包含2个或更多单元格
            if (firstStartRow != firstEndRow)
                firstRows.add(new RowBean(firstStartRow, firstEndRow));
            firstStartRow += size;

            int index = 0;
            for (Map.Entry<String, List<CaCallNames>> listEntry : teacherMap.entrySet()) {
                List<CaCallNames> teacherCallList = listEntry.getValue();
                int teacherLessonNum = teacherCallList.size();

                CaCallNames callNames = teacherCallList.get(0);

                CallNameVoV3 data = new CallNameVoV3();
                if (index == 0) {
                    data.setMemberName(callNames.getMemberName());
                    data.setLessonNum(lessonNum);
                }
                data.setStoreName(callNames.getStoreName());
                data.setTeacherName(callNames.getTeacherName());
                data.setTeacherLessonNum(teacherLessonNum);

                voList.add(data);

                index++;
            }
        }

        String fileName = "会员活动记录统计" + beginDate + "至" + endDate;
        ExcelHandler.exportMergeExcel(response, voList, CallNameVoV3.class, fileName, "自营门店会员活动记录", firstRows, firstColumns);
    }


    @ApiOperation(value = "导出自营门店导读会员累计课时（人事）")
    @PostMapping(value = "/exportMemberAccumulate", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportMemberAccumulate(
            HttpServletResponse response,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid", required = false) String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid", required = false) String storeUid,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        List<Integer> callStatusList = Arrays.asList(1, 2);
        List<Integer> hourTypeList = Arrays.asList(1, 2);

        List<String> selfStoreUidList = null;
        if (StringUtils.isBlank(corpUid) && StringUtils.isBlank(storeUid)) {
            selfStoreUidList = Lists.newArrayList(
                    AccountUtil.WKLS_UID, AccountUtil.QHY_UID, AccountUtil.LHY_UID, AccountUtil.SXMD_UID,
                    AccountUtil.SJGG_UID, AccountUtil.LHTJ_UID
            );
        }

        // 根据导读uid、导读姓名、会员uid、服务uid，获取会员当月的课次数量
        Map<List<String>, List<MemberAccumulateVO>> monthMap = callNameService.getMonthMemberAccumulate(
                corpUid, storeUid, callStatusList, hourTypeList, beginDate, endDate, selfStoreUidList
        );
        if (monthMap == null || monthMap.size() <= 0)
            throw new DescribeException("未查询到数据");

        Set<String> teacherUidList = new HashSet<>();
        for (Map.Entry<List<String>, List<MemberAccumulateVO>> entry : monthMap.entrySet()) {
            List<MemberAccumulateVO> value = entry.getValue();
            for (MemberAccumulateVO vo : value) {
                teacherUidList.add(vo.getTeacherUid());
            }
        }

        // 根据导读uid、导读姓名、会员uid、服务uid分组，获取会员的累计课次数量
        Map<List<String>, Map<String, MemberAccumulateVO>> totalMap = callNameService.getTotalMemberAccumulate(
                corpUid, storeUid, callStatusList, hourTypeList, teacherUidList, "2023-01-01", endDate
        );

        // 会员累计课时差额
        Map<String, Table<String, String, Integer>> lessonLoseNumMap = ScheduleUtil.getLessonLoseNum();

        // 添加表单名称
        List<String> sheetNameList = new ArrayList<>();
        // 添加表单数据
        List<List<MemberAccumulateVO>> dataList = new ArrayList<>();
        for (Map.Entry<List<String>, List<MemberAccumulateVO>> entry : monthMap.entrySet()) {
            List<String> teacherKey = entry.getKey();
            String teacherUid = teacherKey.get(0);
            String teacherName = teacherKey.get(1);
            List<MemberAccumulateVO> valueList = entry.getValue();
            // 导出的数据集合
            List<MemberAccumulateVO> childDataList = new ArrayList<>();

            for (int i = 0; i < valueList.size(); i++) {
                MemberAccumulateVO vo = valueList.get(i);
                // 总累计课时
                long total = 0;
                // 科目累计课时
                long projectTotal = 0;
                Map<String, MemberAccumulateVO> childTotalMap = totalMap.get(Arrays.asList(teacherUid, teacherName, vo.getMemberUid()));
                if (childTotalMap != null && !childTotalMap.isEmpty()) {
                    for (Map.Entry<String, MemberAccumulateVO> voEntry : childTotalMap.entrySet()) {
                        MemberAccumulateVO value = voEntry.getValue();
                        if (value != null)
                            total += NepUtil.nullToZero(value.getTotalNum());
                    }

                    MemberAccumulateVO projectVo = childTotalMap.get(vo.getProjectUid());
                    if (projectVo != null)
                        projectTotal = NepUtil.nullToZero(projectVo.getTotalNum());
                }

                vo.setIndex(i + 1);
                vo.setStoreName(vo.getStoreName());
                vo.setTeacherName(vo.getTeacherName());
                vo.setMemberName(vo.getMemberName());
                vo.setProductName(vo.getProductName());

                Table<String, String, Integer> table = lessonLoseNumMap.get(vo.getTeacherName());
                if (table != null) {
                    // 获取上课次数的差额
                    Integer loseNum = table.get(vo.getMemberName(), vo.getProductName());
                    if (loseNum == null) {
                        // 累计上课数量
                        vo.setTotalNum(total);
                        // 科目累计上课数量
                        vo.setProductTotalNum(projectTotal);
                    } else {
                        System.out.println("loseNum = " + loseNum);
                        // 累计上课数量
                        vo.setTotalNum(total + loseNum);
                        // 科目累计上课数量
                        vo.setProductTotalNum(projectTotal + loseNum);
                        vo.setLoseNum(loseNum);
                    }
                } else {
                    // 累计上课数量
                    vo.setTotalNum(total);
                    // 科目累计上课数量
                    vo.setProductTotalNum(projectTotal);
                }
                childDataList.add(vo);
            }

            sheetNameList.add(teacherName);
            dataList.add(childDataList);
        }
        String fileName = "会员累计课时" + beginDate + "至" + endDate;
        // 导出有多个表单的excel表格
        ExcelHandler.exportSheetsExcel(response, dataList, sheetNameList, MemberAccumulateVO.class, fileName);
    }


    @ApiOperation(value = "导出自营门店的导读带课的会员信息")
    @PostMapping(value = "/exportTeacherTookMember", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportTeacherTookMember(
            HttpServletResponse response,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        // 按自营或联营门店查询
        List<Stores> storesList = storesService.selfAndConsortiumList();
        if (CollectionUtils.isEmpty(storesList)) {
            throw new DescribeException("未查询到门店");
        }
        List<String> storeUidList = storesList.stream().map(Stores::getUid).collect(Collectors.toList());

        List<String> projectUidList = Arrays.asList(ScheduleUtil.JINGDU_UID, ScheduleUtil.WENXUESHE_UID, ScheduleUtil.SIDAMINGZHU_UID, ScheduleUtil.DOUXUEHUI_UID);
        List<CaCallNames> list = callNameService.getCallList(AccountUtil.SELF_CORP_UID, beginDate, endDate, projectUidList);

        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("没有查询到数据");

        Function<CaCallNames, List<String>> compositeKey = vo -> Arrays.asList(vo.getTeacherUid(), vo.getTeacherName());

        Map<List<String>, List<CaCallNames>> map = list.stream().collect(Collectors.groupingBy(compositeKey, Collectors.toList()));

        // 表格头部列的数据
        List<List<String>> headList = new ArrayList<>();
        // 表格第一列默认是门店名称
        headList.add(Collections.singletonList("导读姓名"));
        headList.add(Collections.singletonList("会员数量"));
        headList.add(Collections.singletonList("会员姓名"));
        // 表格内的数据
        List<List<Object>> dataList = new ArrayList<>();

        Table<String, String, String> orderTypeTable = HashBasedTable.create();
        Map<String, List<CaCallNames>> listMap = list.stream().collect(Collectors.groupingBy(CaCallNames::getProjectUid));
        for (Map.Entry<String, List<CaCallNames>> entry : listMap.entrySet()) {
            String projectUid = entry.getKey();
            List<String> memberUidList = entry.getValue().stream().map(CaCallNames::getMemberUid).distinct().collect(Collectors.toList());
            for (String memberUid : memberUidList) {
                Cmservices service = cmservicesService.getMemberConsumesService(storeUidList, memberUid, projectUid);
                if (service != null) {
                    String orderType = service.getOrderType();
                    orderTypeTable.put(memberUid, projectUid, orderType);
                } else {
                    orderTypeTable.put(memberUid, projectUid, "");
                }
            }
        }

        String expType = EnumType.OrderType.EXP.getType();
        for (Map.Entry<List<String>, List<CaCallNames>> entry : map.entrySet()) {
            List<String> key = entry.getKey();
            String teacherUid = key.get(0);
            String teacherName = key.get(1);

            List<CaCallNames> value = entry.getValue();
            List<String> memberNames = new ArrayList<>();

            Map<String, List<CaCallNames>> collect = value.stream().collect(Collectors.groupingBy(CaCallNames::getMemberUid));
            for (Map.Entry<String, List<CaCallNames>> listEntry : collect.entrySet()) {
                String memberUid = listEntry.getKey();
                List<CaCallNames> value1 = listEntry.getValue();
                for (CaCallNames callNames : value1) {
                    String projectUid = callNames.getProjectUid();
                    String orderType = orderTypeTable.get(memberUid, projectUid);
                    if (StringUtils.isNotBlank(orderType) && !orderType.equals(expType)) {
                        memberNames.add(callNames.getMemberName());
                        break;
                    }
                }
            }

            List<Object> data = new ArrayList<>();
            data.add(teacherName);
            if (CollectionUtils.isNotEmpty(memberNames)) {
                data.add(memberNames.size());
                data.add(String.join(",", memberNames));
            } else {
                data.add(0);
                data.add("");
            }

            dataList.add(data);
        }

        // 导出授权码
        String fileName = "导读带课学生" + beginDate + "-" + endDate;
        EasyExcel.write(ExcelHandler.getOutputStream(fileName, response))
                .head(headList).sheet("导读带课学生")
                .doWrite(dataList);
    }


    @ApiOperation(value = "按日期导出自营和联营门的课消及订单详情（财务）")
    @GetMapping(value = "/exportSelfConsumeLesson", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportSelfConsumeLesson(
            HttpServletResponse response,
            @ApiParam(value = "门店标识") @RequestParam(value = "storeUid", required = false) String storeUid,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        // 1.正价 2.赠送 3.体验 4.试听
        List<Integer> hourTypes = Arrays.asList(1, 2, 3, 4);
        List<CaCallNames> list;
        List<Stores> storesList = new ArrayList<>();
        List<String> storeUidList = new ArrayList<>();
        if (StringUtils.isNotBlank(storeUid)) {
            // 按门店标识查询
            Stores stores = storesService.getByUid(storeUid);
            if (stores == null) {
                throw new DescribeException("未查询到门店");
            }
            storesList.add(stores);
            storeUidList.add(storeUid);
        } else {
            // 按自营或联营门店查询
            storesList = storesService.selfAndConsortiumList();
            if (CollectionUtils.isEmpty(storesList)) {
                throw new DescribeException("未查询到门店");
            }
            storeUidList = storesList.stream().map(Stores::getUid).collect(Collectors.toList());
        }
        list = callNameService.consumeListBySelfStore(storeUidList, hourTypes, beginDate, endDate);
        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("没有查询到数据");

        Map<String, String> storeMap = storesList.stream().collect(Collectors.toMap(Stores::getUid, Stores::getStoreName));

        // 获取会员活动消耗的订单号
        List<String> orderCodeList = list.stream()
                .map(CaCallNames::getOrderCode)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        // 本月服务消耗次数
        Map<String, Long> queryServiceCntMap = list.stream()
                .filter(callNames -> StringUtils.isNotBlank(callNames.getServiceUid()))
                .collect(Collectors.groupingBy(CaCallNames::getServiceUid, Collectors.counting()));

        List<CmorderDto> cmorderList = cmordersService.dotListByOrderCodeIn(orderCodeList);

        // 服务记录按订单号分组
        List<CmservicesDto> serviceList = cmservicesService.dtoListByOrderCodesNotChangeOrRefund(null, orderCodeList);
        Map<String, List<CmservicesDto>> serviceMap = serviceList.stream().collect(Collectors.groupingBy(CmservicesDto::getOrderCode));

        // 已开卡且可排活动的服务uid集合，获取消耗数量
        Map<String, Long> consumeMap = CmorderUtil.getConsumeLessonMapByDto(null, serviceList);

        // 表格头部列的数据
        List<List<String>> headList = new ArrayList<>();
        // 表格第一列默认是门店名称
        headList.add(Collections.singletonList("门店名称"));
        headList.add(Collections.singletonList("订单号"));
        headList.add(Collections.singletonList("订单状态"));
        headList.add(Collections.singletonList("会员名称"));
        headList.add(Collections.singletonList("订单金额"));
        headList.add(Collections.singletonList("收款日期"));
        headList.add(Collections.singletonList("收入类型"));
        headList.add(Collections.singletonList("签单人"));
        headList.add(Collections.singletonList("开卡状态"));
        headList.add(Collections.singletonList("开卡日期"));
        headList.add(Collections.singletonList("结束日期"));
        headList.add(Collections.singletonList("是否赠送"));
        headList.add(Collections.singletonList("导读"));
        headList.add(Collections.singletonList("服务名称"));
        headList.add(Collections.singletonList("服务总金额"));
        headList.add(Collections.singletonList("服务总次数"));
        headList.add(Collections.singletonList("剩余次数"));
        headList.add(Collections.singletonList("消耗总次数"));
        headList.add(Collections.singletonList("消耗总金额"));
        headList.add(Collections.singletonList("查询日期消耗次数"));
        headList.add(Collections.singletonList("查询日期消耗金额"));
        // 表格内的数据
        List<List<Object>> dataList = new ArrayList<>();

        int openCardStatus = EnumType.ServiceStatus.OPEN_CARD.getStatus();
        int pauseCardStatus = EnumType.ServiceStatus.PAUSE_CARD.getStatus();

        for (CmorderDto cmorderDto : cmorderList) {
            String orderCode = cmorderDto.getOrderCode();

            List<CmservicesDto> cmservicesDtos = serviceMap.get(orderCode);

            for (int i = 0; i < cmservicesDtos.size(); i++) {
                CmservicesDto serivcie = cmservicesDtos.get(i);

                List<Object> data = new ArrayList<>();
                // 门店名称
                data.add(storeMap.get(cmorderDto.getStoreUid()));
                // 订单号
                data.add(cmorderDto.getOrderCode());
                // 订单号
                data.add(cmorderDto.getOrderStateName());
                // 会员名称
                data.add(cmorderDto.getNewMemberName());
                // 订单金额
                if (i == 0)
                    data.add(cmorderDto.getOrderAmount());
                else
                    data.add("");
                // 收款日期
                if (cmorderDto.getOrderDate() != null)
                    data.add(DateUtil.getDefaultTime2DateStr(cmorderDto.getOrderDate()));
                else
                    data.add("");
                // 收入类型
                if (StringUtils.isNotBlank(cmorderDto.getOrderType()))
                    data.add(EnumType.OrderType.getName(cmorderDto.getOrderType()));
                else
                    data.add("");
                // 签单人
                data.add(cmorderDto.getSaleStaffFullName());
                // 开卡状态
                data.add(serivcie.getStatusName());
                // 开卡日期
                Date begin = serivcie.getBeginDate();
                // 结束日期
                Date end = serivcie.getEndDate();
                if (begin != null && end != null) {
                    data.add(DateUtil.getDefaultTime2DateStr(begin));
                    data.add(DateUtil.getDefaultTime2DateStr(end));
                } else {
                    data.add("");
                    data.add("");
                }
                data.add(serivcie.getIsGift() != null && serivcie.getIsGift().equals(1) ? "赠送" : "非赠送");
                data.add(StringUtils.isNotBlank(serivcie.getStaffFullName()) ? serivcie.getStaffFullName() : "");

                // 服务名称
                data.add(CmorderUtil.getProductName(serivcie));
                // 服务总金额
                Double totalAmount = NepUtil.nullToZero(serivcie.getTotalAmount());
                data.add(totalAmount);

                if (CmorderUtil.isConsumeLesson(serivcie.getLessonStatus(), serivcie.getFreeStatus())) {
                    // 服务总次数
                    int totalLessons = NepUtil.nullToZero(serivcie.getTotalLessons());
                    data.add(totalLessons);

                    if (serivcie.getStatus().equals(openCardStatus) || serivcie.getStatus().equals(pauseCardStatus)) {
                        Double unitAmount = NepUtil.nullToZero(serivcie.getUnitAmount());
                        // 剩余次数
                        int leftLessons = NepUtil.nullToZero(serivcie.getLeftLessons());
                        data.add(leftLessons);
                        // 总消耗次数
                        Long consumeCnt = NepUtil.nullToZero(consumeMap.get(serivcie.getUid()));
                        data.add(consumeCnt);
                        // 如果总消耗次数+剩余次数大于总次数，则重新计算单价
                        if (leftLessons + consumeCnt > totalLessons)
                            unitAmount = DoubleUtil.divFloor(totalAmount, leftLessons + consumeCnt, 4);
                        data.add(DoubleUtil.mul(consumeCnt, unitAmount));
                        // 查询日期消耗次数
                        long consumeNum = NepUtil.nullToZero(queryServiceCntMap.get(serivcie.getUid()));
                        data.add(consumeNum);
                        data.add(DoubleUtil.mul(consumeNum, unitAmount));
                    }
                }

                dataList.add(data);
            }

            dataList.add(new ArrayList<>());
        }

        // 导出授权码
        String fileName = "自营门店的课消及订单详情" + beginDate + "-" + endDate;
        EasyExcel.write(ExcelHandler.getOutputStream(fileName, response))
                .head(headList).sheet("课消及订单详情")
                .doWrite(dataList);
    }


    @ApiOperation(value = "导出自营门店的课消金额统计（人事）")
    @PostMapping(value = "/exportLessonConsumeAmountCount", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportLessonConsumeAmountCount(
            HttpServletResponse response,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        // 按自营或联营门店查询
        List<Stores> storesList = storesService.selfAndConsortiumList();
        if (CollectionUtils.isEmpty(storesList)) {
            throw new DescribeException("未查询到门店");
        }
        List<String> storeUidList = storesList.stream().map(Stores::getUid).collect(Collectors.toList());

        // 1.正价 2.赠送 3.体验 4.试听
        List<Integer> hourTypes = Arrays.asList(1, 2, 3, 4);
        List<CaCallNames> list = callNameService.consumeListBySelfStore(storeUidList, hourTypes, beginDate, endDate);
        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("没有查询到数据");

        // 获取会员活动消耗的订单号
        List<String> orderCodeList = list.stream()
                .map(CaCallNames::getOrderCode)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        List<CmorderDto> cmorderList = cmordersService.dotListByOrderCodeIn(orderCodeList);
        Map<String, CmorderDto> orderMap = cmorderList.stream().collect(Collectors.toMap(CmorderDto::getOrderCode, Function.identity()));
        List<CmservicesDto> serviceList = cmservicesService.dtoListByOrderCodesNotChangeOrRefund(null, orderCodeList);
        Map<String, List<CmservicesDto>> serviceMap = serviceList.stream().collect(Collectors.groupingBy(CmservicesDto::getOrderCode));


        // 获取两个日期之间的所有月份
        String beginDateYM = StringUtils.substringBeforeLast(beginDate, "-");
        String endDateYM = StringUtils.substringBeforeLast(endDate, "-");
        List<String> monthList = DateUtil.getMonthsBetweenDates(beginDateYM, endDateYM);

        // 表格头部列的数据
        List<List<String>> headList = new ArrayList<>();
        // 表格第一列默认是门店名称
        headList.add(Arrays.asList("门店名称", ""));
        // 表格按月份添加头部列
        for (String month : monthList) {
            headList.add(Arrays.asList(month, "正价数量"));
            headList.add(Arrays.asList(month, "正价金额"));
            headList.add(Arrays.asList(month, "体验数量"));
            headList.add(Arrays.asList(month, "体验金额"));
            headList.add(Arrays.asList(month, "赠送数量"));
            headList.add(Arrays.asList(month, "赠送金额"));
            headList.add(Arrays.asList(month, "总数量"));
            headList.add(Arrays.asList(month, "总金额"));
        }
        // 表格内的数据
        List<List<Object>> dataList = new ArrayList<>();

        // 将日期yyyy-MM-dd转为yyyy-MM
        SimpleDateFormat format = new SimpleDateFormat(DateUtil.DEFAULT_YEAR_MONTH_FORMAT1);
        for (CaCallNames callNames : list) {
            String teachDate = callNames.getTeachDate();
            // yyyy-MM-dd 转 yyyy-MM
            Date date = DateUtil.parseDate(teachDate);
            String formatDate = format.format(date);
            callNames.setTeachDate(formatDate);
        }

        Map<String, List<CaCallNames>> storeUidMap = list.stream().collect(Collectors.groupingBy(CaCallNames::getStoreUid));
        for (Map.Entry<String, List<CaCallNames>> listEntry : storeUidMap.entrySet()) {
            String storeUidKey = listEntry.getKey();
            List<CaCallNames> storeCallList = listEntry.getValue();

            String storeName = storeCallList.get(0).getStoreName();
            Map<String, List<CaCallNames>> teachDateMap = storeCallList.stream().collect(Collectors.groupingBy(CaCallNames::getTeachDate, LinkedHashMap::new, Collectors.toList()));

            List<Object> data = new ArrayList<>();
            data.add(storeName);

            // 循环月份
            for (String month : monthList) {
                double payAmount = 0d;
                double expAmount = 0d;
                int payNum = 0;
                int expNum = 0;
                int giftNum = 0;
                List<CaCallNames> teachDateCallList = teachDateMap.get(month);
                if (CollectionUtils.isNotEmpty(teachDateCallList)) {
                    // 会员活动记录按活动课分组
                    Map<String, List<CaCallNames>> lessonCallMap = teachDateCallList.stream().collect(Collectors.groupingBy(CaCallNames::getLessonUid));

                    for (Map.Entry<String, List<CaCallNames>> entry : lessonCallMap.entrySet()) {
                        String key = entry.getKey();
                        List<CaCallNames> value = entry.getValue();

                        Map<Integer, List<CaCallNames>> hourTypeCallMap = value.stream().collect(Collectors.groupingBy(CaCallNames::getHourType));
                        for (Map.Entry<Integer, List<CaCallNames>> hourEntry : hourTypeCallMap.entrySet()) {
                            Integer key1 = hourEntry.getKey();
                            List<CaCallNames> calls = hourEntry.getValue();
                            int size = calls.size();
                            if (key1.equals(1)) {
                                // 正价
                                String projectUid = calls.get(0).getProjectUid();
                                payNum += size;
                                for (CaCallNames call : calls) {
                                    CmorderDto cmorderDto = orderMap.get(call.getOrderCode());
                                    double orderAmount = NepUtil.nullToZero(cmorderDto.getOrderAmount());
                                    List<CmservicesDto> serviceDtoList = serviceMap.get(call.getOrderCode());
                                    payAmount = DoubleUtil.sum(payAmount, getLessonAmount(orderAmount, serviceDtoList));
                                }
                            } else if (key1.equals(2)) {
                                // 赠送
                                giftNum += size;
                            } else if (key1.equals(3)) {
                                // 体验
                                expNum += size;
                                for (CaCallNames call : calls) {
                                    CmorderDto cmorderDto = orderMap.get(call.getOrderCode());
                                    double orderAmount = NepUtil.nullToZero(cmorderDto.getOrderAmount());
                                    // 68元订单计费
//                                    if (orderAmount == 68d && cmorderDto.getOrderDate() != null)
//                                        expAmount = DoubleUtil.sum(expAmount, 5);
                                    List<CmservicesDto> serviceDtoList = serviceMap.get(call.getOrderCode());
                                    expAmount = DoubleUtil.sum(expAmount, getLessonAmount(orderAmount, serviceDtoList));
                                }
                            } else {
                                System.out.println("未知的课消类型:" + key1);
                            }
                        }
                    }
                }
                data.add(payNum);
                data.add(payAmount);
                data.add(expNum);
                data.add(expAmount);
                data.add(giftNum);
                data.add(0d);
                data.add(payNum + expNum + giftNum);
                double amount = DoubleUtil.sum(payAmount, expAmount);
                data.add(amount);
            }

            dataList.add(data);
        }

        // 导出授权码
        String fileName = "自营门店每月课消金额";
        EasyExcel.write(ExcelHandler.getOutputStream(fileName, response))
                .head(headList)
                .sheet("自营门店每月课消金额")
                .doWrite(dataList);
    }

    /**
     * 获取课次的单价
     */
    private double getLessonAmount(double orderAmount, List<CmservicesDto> serviceDtoList) {
        if (orderAmount == 0)
            return 0;

        if (CollectionUtils.isNotEmpty(serviceDtoList)) {
            if (serviceDtoList.size() == 1) {
                CmservicesDto dto = serviceDtoList.get(0);
                if (dto.getIsGift().equals(0))
                    return DoubleUtil.divCeil(orderAmount, NepUtil.nullToZero(dto.getTotalLessons()), 2);
            } else {
                int totalLesson = 0;
                for (CmservicesDto dto : serviceDtoList) {
                    if (dto.getTotalLessons() != null && dto.getIsGift().equals(0))
                        totalLesson += NepUtil.nullToZero(dto.getTotalLessons());
                }
                return DoubleUtil.divCeil(orderAmount, totalLesson, 2);
            }
        }
        return 0;
    }


    @ApiOperation(value = "导出自营门店的课消金额统计V2（人事）")
    @PostMapping(value = "/exportLessonConsumeAmountCountV2", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportLessonConsumeAmountCountV2(
            HttpServletResponse response,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        // 按自营或联营门店查询
        List<Stores> storesList = storesService.selfAndConsortiumList();
        if (CollectionUtils.isEmpty(storesList)) {
            throw new DescribeException("未查询到门店");
        }
        List<String> storeUidList = storesList.stream().map(Stores::getUid).collect(Collectors.toList());

        // 1.正价 2.赠送 3.体验 4.试听
        List<Integer> hourTypes = Arrays.asList(1, 2, 3, 4);
        List<CaCallNames> list = callNameService.consumeListBySelfStore(storeUidList, hourTypes, beginDate, endDate);
        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("没有查询到数据");

        // 获取会员活动消耗的订单号
        List<String> orderCodeList = list.stream()
                .map(CaCallNames::getOrderCode)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        List<CmorderDto> cmorderList = cmordersService.dotListByOrderCodeIn(orderCodeList);
        Map<String, CmorderDto> orderMap = cmorderList.stream().collect(Collectors.toMap(CmorderDto::getOrderCode, Function.identity()));
        List<CmservicesDto> serviceList = cmservicesService.dtoListByOrderCodesNotChangeOrRefund(null, orderCodeList);
        Map<String, List<CmservicesDto>> serviceMap = serviceList.stream().collect(Collectors.groupingBy(CmservicesDto::getOrderCode));


        // 获取两个日期之间的所有月份
        String beginDateYM = StringUtils.substringBeforeLast(beginDate, "-");
        String endDateYM = StringUtils.substringBeforeLast(endDate, "-");
        List<String> monthList = DateUtil.getMonthsBetweenDates(beginDateYM, endDateYM);

        // 表格头部列的数据
        List<List<String>> headList = new ArrayList<>();
        // 表格第一列默认是门店名称
        headList.add(Arrays.asList("门店名称", ""));
        // 表格按月份添加头部列
        for (String month : monthList) {
            headList.add(Arrays.asList(month, "正价数量"));
            headList.add(Arrays.asList(month, "正价金额"));
            headList.add(Arrays.asList(month, "体验数量"));
            headList.add(Arrays.asList(month, "体验金额"));
            headList.add(Arrays.asList(month, "赠送数量"));
            headList.add(Arrays.asList(month, "赠送金额"));
            headList.add(Arrays.asList(month, "总数量"));
            headList.add(Arrays.asList(month, "总金额"));
        }
        // 表格内的数据
        List<List<Object>> dataList = new ArrayList<>();

        // 将日期yyyy-MM-dd转为yyyy-MM
        SimpleDateFormat format = new SimpleDateFormat(DateUtil.DEFAULT_YEAR_MONTH_FORMAT1);
        for (CaCallNames callNames : list) {
            String teachDate = callNames.getTeachDate();
            // yyyy-MM-dd 转 yyyy-MM
            Date date = DateUtil.parseDate(teachDate);
            String formatDate = format.format(date);
            callNames.setTeachDate(formatDate);
        }

        Map<String, List<CaCallNames>> storeUidMap = list.stream().collect(Collectors.groupingBy(CaCallNames::getStoreUid));
        for (Map.Entry<String, List<CaCallNames>> listEntry : storeUidMap.entrySet()) {
            String storeUidKey = listEntry.getKey();
            List<CaCallNames> storeCallList = listEntry.getValue();

            String storeName = storeCallList.get(0).getStoreName();
            Map<String, List<CaCallNames>> teachDateMap = storeCallList.stream().collect(Collectors.groupingBy(CaCallNames::getTeachDate, LinkedHashMap::new, Collectors.toList()));

            List<Object> data = new ArrayList<>();
            data.add(storeName);

            // 循环月份
            for (String month : monthList) {
                double payAmount = 0d;
                double expAmount = 0d;
                int payNum = 0;
                int expNum = 0;
                int giftNum = 0;
                List<CaCallNames> teachDateCallList = teachDateMap.get(month);
                if (CollectionUtils.isNotEmpty(teachDateCallList)) {
                    // 会员活动记录按活动课分组
                    Map<String, List<CaCallNames>> lessonCallMap = teachDateCallList.stream().collect(Collectors.groupingBy(CaCallNames::getLessonUid));

                    for (Map.Entry<String, List<CaCallNames>> entry : lessonCallMap.entrySet()) {
                        String key = entry.getKey();
                        List<CaCallNames> value = entry.getValue();

                        Map<Integer, List<CaCallNames>> hourTypeCallMap = value.stream().collect(Collectors.groupingBy(CaCallNames::getHourType));
                        for (Map.Entry<Integer, List<CaCallNames>> hourEntry : hourTypeCallMap.entrySet()) {
                            Integer key1 = hourEntry.getKey();
                            List<CaCallNames> calls = hourEntry.getValue();
                            int size = calls.size();
                            if (key1.equals(1)) {
                                // 正价
                                String projectUid = calls.get(0).getProjectUid();
                                payNum += size;
                                for (CaCallNames call : calls) {
                                    CmorderDto cmorderDto = orderMap.get(call.getOrderCode());
                                    double orderAmount = NepUtil.nullToZero(cmorderDto.getOrderAmount());
                                    List<CmservicesDto> serviceDtoList = serviceMap.get(call.getOrderCode());
                                    payAmount = DoubleUtil.sum(payAmount, getLessonAmount(orderAmount, serviceDtoList));
                                }
                            } else if (key1.equals(2)) {
                                // 赠送
                                giftNum += size;
                            } else if (key1.equals(3)) {
                                // 体验
                                expNum += size;
                                for (CaCallNames call : calls) {
                                    CmorderDto cmorderDto = orderMap.get(call.getOrderCode());
                                    double orderAmount = NepUtil.nullToZero(cmorderDto.getOrderAmount());
                                    // 68元订单计费
//                                    if (orderAmount == 68d && cmorderDto.getOrderDate() != null)
//                                        expAmount = DoubleUtil.sum(expAmount, 5);
                                    List<CmservicesDto> serviceDtoList = serviceMap.get(call.getOrderCode());
                                    expAmount = DoubleUtil.sum(expAmount, getLessonAmount(orderAmount, serviceDtoList));
                                }
                            } else {
                                System.out.println("未知的课消类型:" + key1);
                            }
                        }
                    }
                }
                data.add(payNum);
                data.add(payAmount);
                data.add(expNum);
                data.add(expAmount);
                data.add(giftNum);
                data.add(0d);
                data.add(payNum + expNum + giftNum);
                double amount = DoubleUtil.sum(payAmount, expAmount);
                data.add(amount);
            }

            dataList.add(data);
        }

        // 导出授权码
        String fileName = "自营门店每月课消金额";
        EasyExcel.write(ExcelHandler.getOutputStream(fileName, response))
                .head(headList)
                .sheet("自营门店每月课消金额")
                .doWrite(dataList);
    }
}